#!/bin/sh
# PCP QA Test No. 1388
# Exercise pmproxy mandatory authentication mode.
#
# Copyright (c) 2017,2019 Red Hat.
#
# NOTE
#	This test is likely to fail unless hostname(1) returns
#	some sort of FQDN.  For example, when hostname was bozo it
#	failed, but when hostname was set (via /etc/hostname in
#	this case) to bozo.localdomain the test passes.
#

seq=`basename $0`
echo "QA output created by $seq"

. ./common.filter
. ./common.secure

_check_series
which curl >/dev/null 2>&1 || _notrun "No curl binary installed"

full_hostname=`hostname`
if echo "$full_hostname" | grep '\.' >/dev/null
then
    :
else
    _notrun "hostname -> $full_hostname, no domain name part"
fi

sasl_notrun_checks saslpasswd2 sasldblistusers2
$pluginviewer -a | grep 'Plugin "sasldb"' >/dev/null
test $? -eq 0 || _notrun "SASL sasldb auxprop plugin unavailable"
$pluginviewer -c | grep 'Plugin "plain"' >/dev/null 2>&1
test $? -eq 0 || _notrun 'No client support for plain authentication'
$pluginviewer -s | grep 'Plugin "plain"' >/dev/null 2>&1
test $? -eq 0 || _notrun 'No server support for plain authentication'

$sudo rm -f $tmp.* $seq.full

signal=$PCP_BINADM_DIR/pmsignal
status=1	# failure is the default!
need_restore=false
groupid=`id -g`
userid=`id -u`
domain=242
loaded=2

_cleanup()
{
    cd $here

    # restore any modified pmcd and pmproxy configuration files
    if $need_restore
    then
	need_restore=false
	_restore_config $PCP_SASLCONF_DIR/pmcd.conf
	_restore_config $PCP_SYSCONF_DIR/labels
        _restore_config $PCP_SYSCONF_DIR/pmproxy
    fi

    if pmprobe -I pmcd.agent.status | grep '"test_python"' >/dev/null
    then
	$sudo rm $PCP_VAR_DIR/config/pmda/$domain.$loaded
	cd $here/pmdas/test_python
	$sudo ./Remove >>$here/$seq.full 2>&1
	$sudo rm -f domain.h.python
	cd $here
    fi

    _service pmcd stop >>$seq.full 2>&1
    _service pmcd start >>$seq.full 2>&1
    _wait_for_pmcd

    if $pmproxy_was_running
    then
	echo "Restart pmproxy ..." >>$here/$seq.full
	_service pmproxy restart >>$here/$seq.full 2>&1
	_wait_for_pmproxy
    else
	echo "Stopping pmproxy ..." >>$here/$seq.full
	_service pmproxy stop >>$here/$seq.full 2>&1
    fi

    $sudo rm -f $tmp.*
}

trap "_cleanup; exit \$status" 0 1 2 3 15

pmproxy_was_running=false
[ -f $PCP_RUN_DIR/pmproxy.pid ] && pmproxy_was_running=true
echo "pmproxy_was_running=$pmproxy_was_running" >>$here/$seq.full

_filter_credentials()
{
    sed \
	-e 's/"groupid": '$groupid',/"groupid": GID/g' \
	-e 's/"userid": '$userid'/"userid": UID/g' \
    #end
}

_filter_username()
{
    sed -e "s/user $username/user USER/"
}

_filter_listusers2()
{
    sed \
        -e "s/^$username/USER/" \
        -e "s/@$full_hostname:/@HOST:/" \
        -e "s/@$hostname:/@HOST:/" \
    #end
}

_filter_json()
{
    tee -a $seq.full | \
    sed -e 's,"machineid": .*,"machineid": "MACHINEID",g' \
        -e 's,"context": .*,"context": "CONTEXT",g' \
        -e 's,"hostname": .*,"hostname": "HOSTNAME",g' \
        -e 's,"domainname": .*,"domainname": "DOMAINNAME",g' \
        -e 's,"source": .*,"source": "SOURCE",g' \
        -e 's,"hostspec": .*,"hostspec": "HOSTSPEC",g' \
    # end
}

_filter_ctx()
{
    tee -a $seq.full | \
    sed -E -e 's/ctx [0-9]+/ctx ?/g'
}

_test_log()
{
    echo && echo "=== $@ ===" | tee -a $here/$seq.full
}

_json_log()
{
    pmjson | tee -a $here/$seq.full
}

# real QA test starts here
_save_config $PCP_SYSCONF_DIR/labels
_save_config $PCP_SYSCONF_DIR/pmproxy
_save_config $PCP_SASLCONF_DIR/pmcd.conf
need_restore=true
$sudo rm -rf $PCP_SYSCONF_DIR/labels/*

# start pmcd in sasldb authenticating mode
echo 'mech_list: plain' >$tmp.sasl
echo "sasldb_path: $tmp.passwd.db" >>$tmp.sasl
$sudo cp $tmp.sasl $PCP_SASLCONF_DIR/pmcd.conf
$sudo chown pcp:pcp $PCP_SASLCONF_DIR/pmcd.conf
ls -l $PCP_SASLCONF_DIR/pmcd.conf >>$seq.full
$sudo -u pcp cat $PCP_SASLCONF_DIR/pmcd.conf >>$seq.full

echo "Creating temporary sasldb, add user running QA to it" | tee -a $seq.full
echo y | saslpasswd2 -p -a pmcd -f $tmp.passwd.db $username

echo "Verify saslpasswd2 has successfully added a new user" | tee -a $seq.full
sasldblistusers2 -f $tmp.passwd.db \
| tee -a $seq.full \
| _filter_listusers2

echo "Ensure pmcd can read the password file" | tee -a $seq.full
$sudo chgrp pcp $tmp.passwd.db
ls -l $tmp.passwd.db >>$seq.full
$sudo -u pcp od -c $tmp.passwd.db >>$seq.full

echo "Start pmcd with this shiny new sasldb"
_service pmcd restart 2>&1 | tee -a $seq.full >$tmp.out
_wait_for_pmcd

if which systemctl >/dev/null 2>&1
then
    $sudo systemctl daemon-reload
fi

echo "Start pmproxy with mandatory authentication"
_service pmproxy stop >/dev/null
_service pmproxy start >>$here/$seq.full 2>&1

echo "Start test Python PMDA to check if username is in per-context state"
cd pmdas/test_python
$sudo ./Install </dev/null \
| _filter_pmda_install
cd $here

_test_log "invalid username with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=nonexisting_user&password=bob" test_python.current_username

_test_log "invalid password with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=$username&password=bob" test_python.current_username

_test_log "correct password with pminfo"
pminfo -f -h "pcp://127.0.0.1?username=$username&password=y" test_python.current_username | _filter_ctx | _filter_username


_test_log "no authentication"
response=$(curl -s "http://localhost:44322/pmapi/context")
echo "${response}" | pmjson | _filter_json
ctx_unauthenticated=$(echo "${response}" | pmpython -c 'import sys,json; print(json.load(sys.stdin)["context"])')

_test_log "invalid username"
curl -s --user nonexisting_user:bob "http://localhost:44322/pmapi/context" | _json_log | _filter_json

_test_log "invalid password"
curl -s --user $username:bob "http://localhost:44322/pmapi/context" | _json_log | _filter_json

_test_log "correct password"
response=$(curl -s --user $username:y "http://localhost:44322/pmapi/context")
echo "${response}" | pmjson | _filter_json | _filter_credentials
ctx_authenticated=$(echo "${response}" | pmpython -c 'import sys,json; print(json.load(sys.stdin)["context"])')

_test_log "using unauthenticated context"
curl -s "http://localhost:44322/pmapi/$ctx_unauthenticated/fetch?names=test_python.current_username" | _json_log | grep '"value"' | _filter_ctx

_test_log "using authenticated context, missing HTTP auth headers (expect failure)"
curl -s "http://localhost:44322/pmapi/$ctx_authenticated/fetch?names=test_python.current_username" | _json_log | _filter_json

_test_log "using authenticated context, with HTTP auth headers (expect success)"
curl -s --user $username:y "http://localhost:44322/pmapi/$ctx_authenticated/fetch?names=test_python.current_username" | _json_log | grep '"value"' | _filter_ctx | _filter_username


echo >>$here/$seq.full
echo "=== pmproxy log ===" >>$here/$seq.full
cat $PCP_LOG_DIR/pmproxy/pmproxy.log >>$here/$seq.full
echo "=== test_python PMDA log ===" >>$here/$seq.full
cat $PCP_LOG_DIR/pmcd/test_python.log >>$here/$seq.full

status=0
exit
